package ch.zbw.iCoach.remo;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Random;

import ch.zbw.iCoach.dameon.*;


/**
 * This class is a main part of the play modus. At the moment of playing it stores all information from an active user
 *  and hold an LanguageList reference.
 *  
 *  This class extend to an "User" class. 
 * 
 * @author Remo Reimann
 * @version Version 1 (release 18.03.2013)
 */
public class ActiveUser extends User {

//data field for storing the languae reference 
private LanguageList languageList;
//data field for storing the amount of round
private int round;
//data field for storing the round size
private int roundSize;
//Array for storing boolean value. 
private Boolean[] matchedStep = null ;
	
	/**
 	* the constructor needs a lot of parameters. First it needs an instance of the user Class. 
 	* This information is in the constructor as a super call. 
 	* 
 	* Second, it needs a reference from the languageList. During the game the program accesses directly to the userlist class
 	* 
 	* the both int value are both initialized with "-1". this is again useful for support investigation.
 	* 
 	* @param lastname		The last name form the playing user
 	* @param firstname		The first name form the playing user
 	* @param username		The user name form the playing user
 	* @param languageList	A reference of an actual LanguageList
 	*/
	public ActiveUser(String lastname, String firstname, String username, 
			LanguageList languageList) {
		super(lastname, firstname, username);
		this.languageList = languageList;
		this.round = -1;
		this.roundSize = -1;
	}
	
	/**
	 * a get method for get the information about the last name
	 * 
	 * @return String		String, which contains the name
	 */
	public String getLastname() {
		return super.getLastname();
	}
	
	/**
	 * a get method for get the information about the first name
	 * 
	 * @return String		String, which contains the name
	 */
	public String getFirstname() {
		return super.getFirstname();
	}
	
	/**
	 * a get method for get the information about the user name
	 * 
	 * @return String		String, which contains the name
	 */
	public String getUsername() {
		return super.getUsername();
	}
	
	/**
	 * This a random method which creates a random number. This number is used during a 
	 * generate process of a new question.
	 * 
	 * @param limit		is an int-value which contains a limit number of the random range.
	 * @return			returns a random generated number.
	 */
	public int random(int limit){
		//local variable which stores temporarily a new Random reference.
		Random random = new Random();
		int randomNumber = 0;
		int nullOffset = 0;
		int upLimit = limit;
		randomNumber = random.nextInt(upLimit) + nullOffset;
		return randomNumber;
	}
	
	/**
	 * This method contains a mathematics algorithm. This algorithm is one of the main part
	 * in the generate process of a new question. Normally on round have 5 steps. But every level
	 * this method calculates how many other question of another level are available. 
	 * 
	 * For example:
	 * 
	 * -	In the first round this method is useless, but with growing level, this method is vital part.
	 * -	In second round it calculates that the round size is 6, because it took the normal size of a round (5) an 
	 * 		add on additional question of the level two.
	 * -	In third round it calculates that the round size is 6, too. Because it took the normal size of a round (5) an 
	 * 		add on additional question of the level three.
	 * -	In fourth round it calculates that the round size is 7, because it took the normal size of a round (5) an 
	 * 		add on additional question of the level two and four.
	 * -	In fifth round it calculates that the round size is 6, because it took the normal size of a round (5) an 
	 * 		add on additional question of the level five.
	 * -	In sixth round it calculates that the round size is 7, because it took the normal size of a round (5) an 
	 * 		add on additional question of the level three and six.
	 * 
	 * and so on....
	 * 
	 * The most impressing feature is, that this method has no limit.
	 */
	public void checkRound(){
		matchedStep = null;
		int currentLevelSize = -1;
		int dividate = -1;
		int resultDiv = -1;
		int modulo = -1;
		
		//checks the possibleLevelSize by checking all parent keys of all word.
		//the minimum size is one and again there is no limit!
		for(int i = 0; i<languageList.getSize();i++){
			Language temp;
			temp = languageList.getlang(i);
			if (currentLevelSize < temp.getParentKey()){
				currentLevelSize = temp.getParentKey();
				
			}
		}
		//crates a new boolean array the size of this array depends on the amount of levels.
		//the minimum size is 3, otherwise the will be an OutOfBOund-exception.
		if(currentLevelSize >1){
			matchedStep = new Boolean[currentLevelSize +1];
		}
		if (currentLevelSize <= 1){
			matchedStep = new Boolean[currentLevelSize +3];
		}
		//set the whole boolean array to false.
		Arrays.fill(matchedStep, Boolean.FALSE);
			//a for loop which takes the current level size for the maximum loop limit
			for (int c = 0; c <= currentLevelSize; c ++){
				//makes an modulo operation
				//the operation takes the played round and does an module operation with
				//the smallest possible up to the current Level size.
				modulo = round % (c+1);
				// if the modulo result is 0, the index in the boolean array will set the boolean value to true. 
				if (modulo == 0){
					//the index match with real value of the modulo operation. 
					try {
						matchedStep[c+1] = true;
					} catch (Exception e) {
						// wrong index selceted
						System.out.println("wrong index matched step");
					}
				}
			}
	}
	
	
	/**
	 * This method calculates with support of the method "checkRound" amount of the next round.
	 * This is needed for different Levelsize
	 * 
	 * @return		returns a int value, which contains the new round size
	 */
	public int getRoundSize(){
		//Check from which level the words can be chosen.
		this.checkRound();
		this.roundSize = 0;
		System.out.println("matchedStepSize: " + matchedStep.length);
		for (int z = 0; z < matchedStep.length; z++){
			if (matchedStep[z] == true){
				this.roundSize ++;
			}
		}
		//the program has to add the 4, otherwise you just have the amount of additional round
		this.roundSize = this.roundSize + 4;
		//returns the total amount of the next round
		return this.roundSize;
	}
	
	/**
	 * This method depends on the two other "getRoundSize" and "checkRound".
	 * 
	 * The first 5 questions are generated from the basic Level (levelSize = 1). The following questions depends on the playing round
	 * If there are steps (view method "checkRound") matched on a levelSize, additional question will generate.
	 * 
	 * - 	The first step in the whole procedure is to initialize all local variable. 
	 * - 	The second step is a query and a handle process . Here the program makes sure that every additional questions are generated from
	 * 		each possible level. 
	 * -	The third step is an if query which checks the transmission. There are two different algorithm. The border is at 5 Transmission.
	 * -	The fourth step is to generate a random answer
	 * -	The fifth step is to find the right answer in the right language.  
	 * -	The sixth step is to find two  random wrong possible answer in the right language.
	 * 
	 * @param langQ			ID of the question language
	 * @param langA			ID of the answer language
	 * @param transmission	Amount of a transmission during a round.
	 * @return				returns a string which contains the askingWord, rightAnswer, wrongAnswer1, wrongAnswer2
	 */
	public String generateQuestion(int langQ, int langA, int transmission){
		//this is a boolean value which is needed for the loopControl 
		boolean loopControl1 = false;
		boolean loopControl2 = false;
		boolean loopControl3 = false;
		boolean loopControl4 = false;
		//stores indexes 
		//Q = question
		// A = Answer
		int tempIndexQ = -1;
		int tempIndexA = -1;
		int searchWrong1 = -1;
		int searchWrong2 = -1;
		int primaryKey = -1;
		int counter = -1;
		//Stores the needed words
		String askingWord = null;
		String rightAnswer = null;
		String wrongAnswer = null;
		String defaultUserName = "default";
		Language searchLangID = null;
		Language defineWrong1 = null;
		Language defineWrong2 = null;
		
		//Check if all of the possible additional questions are generated.
		//Description above in step two!
		counter = 0;
		for (int c = 0; c < matchedStep.length; c++){
			if (matchedStep[c] == false) {
				counter ++;
			}
			if(counter == matchedStep.length) 
				loopControl4 = true;
			System.out.println("All additional levels processed");
		}
		
		//the do-Loop runs through the loop as long as the LangID from the random 
		//generated index matches the langQ.
		if ((transmission >=5) && (loopControl4 != true)){
			//a while loop runs true the the array. It spots as soon as the loopControl3 is true.
			while (loopControl3 != true){
				tempIndexQ = this.random(languageList.getSize());
				Language temp = languageList.getlang(tempIndexQ);
				//for loop for searching a random question word and id
				for (int a = 0; a < matchedStep.length ; a++){
					if ((true == matchedStep[a]) && (temp.getLangID() == langQ) && (loopControl3 != true)&&
							((temp.getUserName().equals(super.getUsername()) || (temp.getUserName().equals(defaultUserName))))){
						matchedStep[a] = false;
						a = matchedStep.length - 1;
						loopControl3 = true;
						//takes the word from temp and save it. 
						//the same happen to primary key
						askingWord = temp.getWord();
						primaryKey = temp.getPrimaryKey();
					}
				}
			}
			//For loop for finding the the answer index which is connect to the question word.
			for(int b = 0; b < this.languageList.getSize(); b++) {	
				Language temp2 = languageList.getlang(b);
				//find the index of the answer to the question
				if ((langA == temp2.getLangID()) && (primaryKey == temp2.getPrimaryKey())){
					tempIndexA = b;
					}
			}
			//reads the word from the temp3 and safes it into the local variable "right Answer
			Language temp3 = languageList.getlang(tempIndexA);
			rightAnswer = temp3.getWord();
			}
			//this algorithm runs when the transmission. 
			if ((transmission <5) || loopControl4 == true){
				//Do-while loop which generates an new random index.
				//This stops when both ID are the same.
				do{
					tempIndexQ = this.random(languageList.getSize());
					searchLangID = languageList.getlang(tempIndexQ);
				} while (langQ != searchLangID.getLangID());
			
				Language wordCount = languageList.getlang(tempIndexQ);
				askingWord = wordCount.getWord();
				primaryKey = wordCount.getPrimaryKey(); 
				for(int i = 0; i < this.languageList.getSize(); i++) {
					Language temp2 = languageList.getlang(i);
					if ((langA == temp2.getLangID()) && (primaryKey == temp2.getPrimaryKey())){
						//safe the index when  the langID and primary key are both "true".
						tempIndexA = i;	
					}
				
				}
				//reads the word from the temp3 and safes it into the local variable "right Answer
				Language temp3 = languageList.getlang(tempIndexA);
				rightAnswer = temp3.getWord();
				//Do-while loop which generates an new random index.
				//This stops when both ID are the same.
				do{
					tempIndexQ = this.random(languageList.getSize());
					searchLangID = languageList.getlang(tempIndexQ);
				} while (langQ != searchLangID.getLangID());
				//safe the index after the do-while loop
				Language wordCount1 = languageList.getlang(tempIndexQ);
				askingWord = wordCount1.getWord();
				primaryKey = wordCount1.getPrimaryKey(); 
				for(int i = 0; i < this.languageList.getSize(); i++) {
					Language temp2 = languageList.getlang(i);
					if ((langA == temp2.getLangID()) && (primaryKey == temp2.getPrimaryKey())){
						tempIndexA = i;
						}
					}
					Language temp4 = languageList.getlang(tempIndexA);
					rightAnswer = temp4.getWord();
					}
		//while loop generate the first wrong questions
		while (loopControl1 == false){
			searchWrong1 = this.random(languageList.getSize());
			defineWrong1 = languageList.getlang(searchWrong1);
			if ((defineWrong1.getLangID() == langA) && (true != rightAnswer.equals(defineWrong1.getWord())) ){
				loopControl1 = true;
				wrongAnswer = defineWrong1.getWord();
			}
			
		}
		//while loop generate the second wrong questions
		while (loopControl2 == false){
			searchWrong2 = this.random(languageList.getSize());
			defineWrong2 = languageList.getlang(searchWrong2);
			if ((defineWrong2.getLangID() == langA) && (true != rightAnswer.equals(defineWrong2.getWord())) && (true != wrongAnswer.equals(defineWrong2.getWord()))){
				loopControl2 = true;
			}
			
		}

		//the four steps below takes the words out of langList, after the generating process and 
		//safe the word into the local variable wrongAnswer1  and wrongAnswer2.
		Language temp4 = languageList.getlang(searchWrong1);
		Language temp5 = languageList.getlang(searchWrong2);
		String wrongAnswer1 = temp4.getWord();
		String wrongAnswer2 = temp5.getWord();
		//returns a string value
		return askingWord +","+ rightAnswer +","+ wrongAnswer1 +","+ wrongAnswer2;
	}
	
	/**
	 * If a player have answered a question right, the parentKey (Level) has to be rewritten.
	 * This method find the word in the languageList takes the reference, delete the reference in the languageList,
	 * change the value in the local reference and add it again to the languageList
	 * 
	 * This method change the level of both word (question and answer word)
	 * 
	 * @param langQ		ID for question words
	 * @param langA		ID for asking words
	 * @param wordQ		Question Word
	 * @param wordA		Answer Word
	 */
	public void rightAnswer(int langQ, int langA, String wordQ, String wordA){
		boolean changeLevel1 = false;
		boolean changeLevel2 = false;
		int indexQ = 0;
		int indexA = 0;
		int parentKeyQ = 0;
		int parentKeyA = 0;
		//Question word:
		//while loop runs through the arraylist, find the word,
		//save local the reference, delete the reference in the langList,
		//change parentKey, add it again to the langList
		while((changeLevel1 != true) && (indexQ < languageList.getSize())){
			Language tempWordQ = languageList.getlang(indexQ);
				if((tempWordQ.getWord().equals(wordQ)) && (langQ == tempWordQ.getLangID())){
					changeLevel1 = true;
					languageList.deleteLanguage(indexQ);
					parentKeyQ = tempWordQ.getParentKey() + 1;
					tempWordQ.setParentKey(parentKeyQ);
					languageList.addLanguage(tempWordQ);
					
			}
			indexQ ++;
		}
		//Answer word:
		//while loop runs through the arraylist, find the word,
		//save local the reference, delete the reference in the langList,
		//change parentKey, add it again to the langList
		while((changeLevel2 != true) && (indexA < languageList.getSize())){
			Language tempWordA = languageList.getlang(indexA);
			if((tempWordA.getWord().equals(wordA)) && (langA == tempWordA.getLangID())){
				changeLevel2 = true;
				languageList.deleteLanguage(indexA);
				parentKeyA = tempWordA.getParentKey() + 1;;
				tempWordA.setParentKey(parentKeyA);
				languageList.addLanguage(tempWordA);
			}
			indexA ++;
		}
	}
	
	/**
	 * If a player have answered a question right, the parentKey (Level) has to be rewritten.
	 * This method find the word in the languageList takes the reference, delete the reference in the languageList,
	 * change the value in the local reference and add it again to the languageList
	 * 
	 * This method change the level of both word (question and answer word)
	 * 
	 * @param langQ		ID for question words
	 * @param langA		ID for asking words
	 * @param wordQ		Question Word
	 * @param wordA		Answer Word
	 */
	public void wrongAnswer(int langQ, int langA, String wordQ, String wordA){
		boolean changeLevel1 = false;
		boolean changeLevel2 = false;
		int indexQ = 0;
		int indexA = 0;
		int parentKeyQ = 0;
		int parentKeyA = 0;
		//Question word:
		//while loop runs through the arraylist, find the word,
		//save local the reference, delete the reference in the langList,
		//change parentKey, add it again to the langList
		while((changeLevel1 != true) && (indexQ < languageList.getSize())){
			Language tempWordQ = languageList.getlang(indexQ);
			if((tempWordQ.getWord().equals(wordQ)) && (langQ == tempWordQ.getLangID())){
				changeLevel1 = true;
				
				if (tempWordQ.getParentKey() > 1)
					languageList.deleteLanguage(indexQ);
					parentKeyQ = tempWordQ.getParentKey() - 1;;
					tempWordQ.setParentKey(parentKeyQ);
					languageList.addLanguage(tempWordQ);
					
			}
			indexQ ++;
		}
		//Answer word:
		//while loop runs through the arraylist, find the word,
		//save local the reference, delete the reference in the langList,
		//change parentKey, add it again to the langList
		while((changeLevel2 =! true) && (indexQ < languageList.getSize())){
			Language tempWordA = languageList.getlang(indexA);
			if((tempWordA.getWord().equals(wordA)) && (langA == tempWordA.getLangID())){
				changeLevel2 = true;
				
				if (tempWordA.getParentKey() > 1){
					languageList.deleteLanguage(indexA);
					parentKeyA -= tempWordA.getParentKey() -1;
					tempWordA.setParentKey(parentKeyA);
					languageList.addLanguage(tempWordA);
				}
			}
			indexA ++;
		}	
	}
	
	/**
	 * This method is for setting a new round
	 * 
	 * @param round		an int value which describes the round amount.
	 */
	public void setNewRound(int round){
		this.round = round;
	}
}
